import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.*;

public class Field {

	private ArrayList<Zone> zones;
	private Point[] startingPositions;
	private int redScore, blueScore;
	private Dimension dimension;
	protected static final int REBOUND_RUMBLE = 1, LOGOMOTION = 2;
	private static GamePiece closestPiece;
	private int fieldType;
	private int nFieldZones = 0;
	private Zone redScoring, blueScoring;

	//Based on the type of field, construct zones
	//Add these zones to an array of zones to construct a field object
	public Field(int fieldType){
		zones = new ArrayList<Zone>();
		this.fieldType = fieldType;

		//Rebound Rumble case
		if(fieldType == Field.REBOUND_RUMBLE){
			//Collection zones
			SafeZone redSafeZone = new SafeZone(new Point(600, 0), 600, 100, Robot.Alliance.red, false);
			zones.add(redSafeZone);	

			SafeZone blueSafeZone = new SafeZone(new Point(0, 500), 600, 100, Robot.Alliance.blue, false);
			zones.add(blueSafeZone);

			//Keys
			SafeZone redKey = new SafeZone(new Point(200, 200), 100, 100, Robot.Alliance.red, true);
			zones.add(redKey);

			SafeZone blueKey = new SafeZone(new Point(850, 200), 100, 100, Robot.Alliance.blue, true);
			zones.add(blueKey);

			//Scoring zones
			ScoringZone blueScoringZone = new ScoringZone(new Point (1150, 200), 50, 200, Robot.Alliance.blue);
			zones.add(blueScoringZone);
			blueScoring = blueScoringZone;

			ScoringZone redScoringZone = new ScoringZone(new Point(0, 200), 50, 200, Robot.Alliance.red);
			zones.add(redScoringZone);
			redScoring = redScoringZone;

			nFieldZones = 6;
		}

		//Logomotion case
		else if(fieldType == Field.LOGOMOTION){
			//Collection zones
			SafeZone redSafeZoneOne = new SafeZone(new Point(0,0), RoboticsProjectPanel.X_DIMENSION/2 - 100, 100, Robot.Alliance.red, false);
			zones.add(redSafeZoneOne);

			SafeZone redSafeZoneTwo = new SafeZone(new Point(0 ,RoboticsProjectPanel.Y_DIMENSION - 100), RoboticsProjectPanel.X_DIMENSION/2 - 100, 100, Robot.Alliance.red, false);
			zones.add(redSafeZoneTwo);

			SafeZone blueSafeZoneOne = new SafeZone(new Point(RoboticsProjectPanel.X_DIMENSION/2 + 100,0), RoboticsProjectPanel.X_DIMENSION/2 - 100, 100, Robot.Alliance.blue, false);
			zones.add(blueSafeZoneOne);

			SafeZone blueSafeZoneTwo = new SafeZone(new Point(RoboticsProjectPanel.X_DIMENSION/2 + 100, RoboticsProjectPanel.Y_DIMENSION - 100), RoboticsProjectPanel.X_DIMENSION/2 - 100, 100, Robot.Alliance.blue, false);
			zones.add(blueSafeZoneTwo);

			//Scoring zones
			ScoringZone redScoringZone = new ScoringZone(new Point(RoboticsProjectPanel.X_DIMENSION - 150, 100), 150, RoboticsProjectPanel.Y_DIMENSION - 200, Robot.Alliance.red);
			zones.add(redScoringZone);
			redScoring = redScoringZone;

			ScoringZone blueScoringZone = new ScoringZone(new Point(0, 100), 150, RoboticsProjectPanel.Y_DIMENSION - 200, Robot.Alliance.blue);
			zones.add(blueScoringZone);
			blueScoring = blueScoringZone;

			nFieldZones = 6;
		}
	}

	public int getFieldType(){
		return fieldType;
	}

	public ArrayList<Zone> getZoneList(){
		return zones;
	}

	public void addZone(Zone zone){
		zones.add(zone);
	}

	//Converts the robots (based on updated position) to zones for collision avoidance
	public synchronized void updateBoundaries(Robot[][] robots) {

		for(int z=0; z < 3; z++){

			int i =0;

			zones.set(nFieldZones + z, new Zone(new Point(robots[0][i].getXPosition() - Robot.X_DIMENSION/2, robots[0][i].getYPosition() - Robot.Y_DIMENSION/2),
					Robot.X_DIMENSION, Robot.Y_DIMENSION, robots[0][i].getAlliance()));

			zones.set(nFieldZones + 3 + z, new Zone(new Point(robots[1][i].getXPosition()- Robot.X_DIMENSION/2, robots[1][i].getYPosition()- Robot.Y_DIMENSION/2),
					Robot.X_DIMENSION, Robot.Y_DIMENSION, robots[1][i].getAlliance()));
			i++;
		}
	}

	//Draws field by drawing all zones
	public void drawField(Graphics page) {
		for(int i=0; i<zones.size() - 6; i++){
			zones.get(i).drawZone(page);
		}
	}

	//Gets the alliance of the zone in which a point exists 
	//Non-neutral zones take precedence
	public synchronized Robot.Alliance getZone(Point point){
		Robot.Alliance alliance = Robot.Alliance.neutral;

		for(int i=0; i<zones.size()-6; i++){
			Zone temp = zones.get(i);
			if(point.x<temp.getXMax() -100 && 
					point.x>temp.getXMin()+100 &&
					point.y<temp.getYMax()-100 &&
					point.y>temp.getYMin()+100){
				if(temp.getAlliance() == Robot.Alliance.blue){
					alliance = Robot.Alliance.blue;
				}
				else if(temp.getAlliance() == Robot.Alliance.red){
					alliance = Robot.Alliance.red;
				}
				else{
					alliance = Robot.Alliance.neutral;
				}
			}
			else{}
		}
		return alliance;
	}

	//Locates the closest GamePiece to a given robot
	public synchronized GamePiece findClosestGamePiece(Robot aRobot){

		Point robotPosition = new Point(aRobot.getXPosition(), aRobot.getYPosition());

		double previousDistance = distance(robotPosition, RoboticsProjectPanel.gamePieceList.get(0).getPosition());
		double nextDistance;

		closestPiece = RoboticsProjectPanel.gamePieceList.get(0);

		//King of the hill
		for(int i = 0; i < RoboticsProjectPanel.gamePieceList.size(); i++){

			//Checks if carried or previously targeted
			//No two robots should target the same GamePiece simultaneously
			if(!RoboticsProjectPanel.gamePieceList.get(i).isCarried() && !RoboticsProjectPanel.gamePieceList.get(i).isTargeted()){

				Robot.Alliance tempAlliance = this.getZone(RoboticsProjectPanel.gamePieceList.get(i).getPosition());
				if(tempAlliance == aRobot.getAlliance() || tempAlliance ==Robot.Alliance.neutral){

					nextDistance = distance(robotPosition, RoboticsProjectPanel.gamePieceList.get(i).getPosition());

					if(nextDistance <= previousDistance){
						closestPiece = RoboticsProjectPanel.gamePieceList.get(i);	

						previousDistance = nextDistance;
					}
				}
			}
		}
		return closestPiece;		
	}

	//Generic distance calculator
	public static synchronized double distance(Point a, Point b) {
		return Math.sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
	}

	//Finds the scoring zone based on an alliance
	//Desired scoring position will be somewhat removed from wall
	public synchronized Point findScoringZone(Robot.Alliance alliance){
		Point point = null;
		if(alliance == Robot.Alliance.blue){
			point = new Point(blueScoring.getUpperLeft().x+blueScoring.getxSize()/2-100, 
					blueScoring.getUpperLeft().y+blueScoring.getySize()/2);
		}
		else if(alliance == Robot.Alliance.red){
			point = new Point(redScoring.getUpperLeft().x+redScoring.getxSize()/2+100, 
					redScoring.getUpperLeft().y+redScoring.getySize()/2);
		}
		return point;

	}

	//if a robot cannot reach its target for any reason, change the robot's target GamePiece
	public synchronized GamePiece acquireNewTarget(Robot robot, Point index){
		ArrayList<Point> targetList = new ArrayList<Point>();
		if(robot.getState() == Robot.State.score){
			//do nothing
		}
		
		//if the robot is in collection state, find the next closest GamePiece
		else if(robot.getState() == Robot.State.collect){
			//add all of the GamePieces
			for(int i=0; i<RoboticsProjectPanel.gamePieceList.size(); i++){
				targetList.add(RoboticsProjectPanel.gamePieceList.get(i).getPosition());
			}
		}
		
		//King of the hill
		double previousDistance = distance(targetList.get(0), robot.getPosition());
		Point finalPoint = targetList.get(0);
		GamePiece finalGamePiece = RoboticsProjectPanel.gamePieceList.get(0);
		for(int n=1; n < targetList.size(); n++){
			double newDistance = distance(targetList.get(n), robot.getPosition());
			if(newDistance < previousDistance){
				previousDistance = newDistance;
				finalPoint = targetList.get(n);
				finalGamePiece = RoboticsProjectPanel.gamePieceList.get(n);
			}
		}
		return finalGamePiece;
	}

}